package com.zhudi.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.shaded.com.google.common.reflect.TypeToken;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.zhudi.expection.BusinessException;
import com.zhudi.mapper.UserMapper;
import com.zhudi.model.dto.InterfaceModel;
import com.zhudi.model.dto.InterfaceDTO;
import com.zhudi.model.dto.UserClientModel;
import com.zhudi.model.emun.AuthEnum;
import com.zhudi.model.entity.Interface;
import com.zhudi.model.entity.User;
import com.zhudi.model.request.InterfaceAddRequest;
import com.zhudi.model.request.InterfaceSearchRequest;
import com.zhudi.model.request.InterfaceUpdateRequest;
import com.zhudi.model.request.PageRequest;
import com.zhudi.model.vo.InterfaceVO;
import com.zhudi.service.InterfaceService;
import com.zhudi.mapper.InterfaceMapper;
import com.zhudi.utils.BeanUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;


import java.io.*;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.zhudi.commen.ErrorCode.PARAMS_ERROR;
import static com.zhudi.commen.ErrorCode.SYSTEM_ERROR;

/**
* @author 朱朱朱朱蒂
* @description 针对表【interface(接口表)】的数据库操作Service实现
* @createDate 2024-04-16 18:19:06
*/
@Service
public class InterfaceServiceImpl extends ServiceImpl<InterfaceMapper, Interface>
implements InterfaceService{

    @Resource
    InterfaceMapper interfaceMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    Configuration freemarkerConfiguration;


    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int addInterface(InterfaceAddRequest interfaceAddRequest, User loginUser) {
        //分为添加进数据库和生成对应类两大部分

        if (interfaceAddRequest==null||loginUser==null){
            throw new BusinessException(PARAMS_ERROR);
        }
        //对数据进行合法性校验
        //1. 强制将接口名称首字母大写
        String interfaceAddRequestName = interfaceAddRequest.getName();
        interfaceAddRequestName=Character.toUpperCase(interfaceAddRequestName.charAt(0)) + (interfaceAddRequestName.length() > 1 ? interfaceAddRequestName.substring(1) : "");


        //2. 将请求地址拆分出端口和url
        String fullPath = interfaceAddRequest.getUrl();
        String port;
        String interfaceUrl;
        //检查一下是否有加https://
        String regex  ="^(http|https)://.*$";
        boolean matches = Pattern.matches(regex, fullPath);
        if (!matches){
            throw new BusinessException(PARAMS_ERROR,"url地址应该以http/https开头");
        }
        try {
            URL url = new URL(fullPath);
            port = url.getHost();
            interfaceUrl = url.getPath();
        } catch (MalformedURLException e) {
            throw new BusinessException(PARAMS_ERROR,"接口的URL不正确");
        }
        //添加进数据库
        Long loginUserId = loginUser.getId();
        if (loginUserId<=0){
            throw new BusinessException(PARAMS_ERROR);
        }
        //检查是否有这个loginUserId
        if (!userMapper.exists(new QueryWrapper<>(loginUser))) {
            throw new BusinessException(PARAMS_ERROR,"不存在此用户");
        }
        String groupName = interfaceAddRequest.getGroupName();

        QueryWrapper<Interface> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name",interfaceAddRequestName);
        queryWrapper.eq("port",port);
        queryWrapper.eq("group_name",groupName);
        Interface anInterface = interfaceMapper.selectOne(queryWrapper);
        if (anInterface!=null){
            throw new BusinessException(PARAMS_ERROR,"此分组下已经存在该名称接口");
        }


        Interface newInterface = new Interface();
        //设置端口和url
        //设置创建者的id，默认是当前登录的用户
        newInterface.setCreatorId(loginUserId);
        //复制剩下的数值
        org.springframework.beans.BeanUtils.copyProperties(interfaceAddRequest,newInterface);
        if (port!=null&&interfaceUrl!=null) {
            newInterface.setPort(port);
            newInterface.setUrl(interfaceUrl);
        }
        int insert = interfaceMapper.insert(newInterface);

        //接下来需要在对应的sdk项目中生成对应的类以及在对应的client中生成对应的方法。
        InterfaceModel interfaceModel = new InterfaceModel();
        interfaceModel.setMethod(interfaceAddRequest.getMethod());
        //设置网关的调用路径
        interfaceModel.setPath(interfaceAddRequest.getPath());
        interfaceModel.setClassName(interfaceAddRequestName);

        //接下来因为interfaceAddRequest中的parameter是一个json格式的数据，所以需要从中解析出来
        String parameters = interfaceAddRequest.getParameter();
        Map<String, Map<String, Object>> parameterMap = parseParameters(parameters);
        interfaceModel.setParameters(parameterMap);
        //在sdkclient中增加对应的方法
        String clientPath = "./myInterfaceSDK/src/main/java/com/zhudi/model/UserClient.java";
        //在sdk中创建对应的类
        //todo:这里最好改造为可以指定在哪一个sdk中创建
        try {
            generateInterfaceClass(interfaceModel);
            updateClient(clientPath);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(SYSTEM_ERROR,"生成接口类失败");
        }

        return insert;

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void generateInterfaceClass( InterfaceModel interfaceModel) throws IOException, TemplateException {
        if (interfaceModel==null){
            throw new BusinessException(PARAMS_ERROR);
        }

        //创建模板对象，加载指定模板
        Template template = freemarkerConfiguration.getTemplate("interfaceTemplate.java.ftl");

        String fileDirectory = "./myInterfaceSDK/src/main/java/com/zhudi/model/request";
        String filePath = fileDirectory + "/" + interfaceModel.getClassName() + "Request.java";

        // 创建文件的目录
        File directory = new File(fileDirectory);

        if (!directory.exists()) {
            boolean mkdirs = directory.mkdirs();
        }

        // 使用try-with-resources自动关闭资源
        try (Writer out = new FileWriter(filePath)) {
            // 处理模板并写入文件
            template.process(interfaceModel, out);
        } catch (IOException | TemplateException e) {
            // 添加错误处理
            throw new BusinessException(SYSTEM_ERROR,"生成文件失败");
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateClient(String clientPath) throws IOException {
        //todo 改进这个方法，使其不止能够更新UserClient
        QueryWrapper<Interface> queryWrapper = new QueryWrapper<>();
        //从数据库读取这个client对应的接口数据，包括接口名称、

        queryWrapper.eq("group_name","USER");
        queryWrapper.select("name");
        List<Interface> interfaces = interfaceMapper.selectList(queryWrapper);

        //将接口名称转为大驼峰和小驼峰，便于freemarker生成数据，不在freemarker做转换
        //key为大驼峰，value为小驼峰也就是 GetUser,getUser
        //创建数据模型
        Map<String, String> interfaceMap = interfaces.stream().collect(Collectors.toMap(Interface::getName,anInterface ->
                Character.toLowerCase(anInterface.getName().charAt(0)) + (anInterface.getName().length() > 1 ? anInterface.getName().substring(1) : "")));

        UserClientModel userClientModel = new UserClientModel();
        userClientModel.setInterfaceMap(interfaceMap);
        //创建模板对象，加载指定模板
        Template template = freemarkerConfiguration.getTemplate("UserClient.java.ftl");


        // 使用try-with-resources自动关闭资源
        try (Writer out = new FileWriter(clientPath)) {
            // 处理模板并写入文件
            template.process(userClientModel, out);
        } catch (IOException | TemplateException e) {
            // 添加错误处理
            throw new BusinessException(SYSTEM_ERROR,"生成文件失败");
        }


    }

    @Override
    public Boolean deleteInterface(Long interfaceId, User loginUser) {

        if (loginUser==null||interfaceId==null){
            throw new BusinessException(PARAMS_ERROR);
        }
        int role = loginUser.getRole();
        //如果是管理员的话直接删除
        if(AuthEnum.ADMIN.getValue()==role){
            return interfaceMapper.deleteById(interfaceId)==1;
        }else {
            //如果不是管理员，则要判断要删除的接口是否是当前这个用户的
            //先判断是否有id
            Long loginUserId = loginUser.getId();
            if(loginUserId==null){
                throw new BusinessException(PARAMS_ERROR);
            }
            QueryWrapper<Interface> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",interfaceId);
            queryWrapper.eq("creator_id",loginUser.getId());
            if( interfaceMapper.selectOne(queryWrapper)==null){
                throw new BusinessException(PARAMS_ERROR,"要删除的接口不存在或者你无权删除此接口");
            }
            return interfaceMapper.deleteById(interfaceId)==1;
        }

    }

    @Override
    public int updateInterface(InterfaceUpdateRequest interfaceUpdateRequest, User loginUser) {
        if (loginUser==null||interfaceUpdateRequest==null){
            throw new BusinessException(PARAMS_ERROR);
        }
        Interface newInterface = new Interface();
        org.springframework.beans.BeanUtils.copyProperties(interfaceUpdateRequest,newInterface);
        int role = loginUser.getRole();
        //如果是管理员的话直接更新
        if(AuthEnum.ADMIN.getValue()==role){
            return interfaceMapper.updateById(newInterface);
        }else {
            //如果不是管理员，则要判断要删除的接口是否是当前这个用户的
            //先判断是否有id
            Long loginUserId = loginUser.getId();
            if(loginUserId==null){
                throw new BusinessException(PARAMS_ERROR);
            }
            QueryWrapper<Interface> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",newInterface.getId());
            queryWrapper.eq("creator_id",loginUser.getId());
            if( interfaceMapper.selectOne(queryWrapper)==null){
                throw new BusinessException(PARAMS_ERROR,"要更新的接口不存在或者你无权删更新此接口");
            }
            return interfaceMapper.updateById(newInterface);
        }
    }

    @Override
    public Page<InterfaceDTO> searchInterface(InterfaceSearchRequest interfaceSearchRequest, PageRequest pageRequest) {
        //todo 完善这个功能
        return null;
    }

    @Override
    public Page<InterfaceVO> listInterfaceByPage(PageRequest pageRequest) {
        if(pageRequest==null){
            throw new BusinessException(PARAMS_ERROR);
        }
        QueryWrapper<Interface> queryWrapper = new QueryWrapper<>();
        Page<Interface> selectPage = interfaceMapper.selectPage(new Page<>(pageRequest.getPageNum(),pageRequest.getPageSize()), queryWrapper);

        return BeanUtils.mapEntityPageToVoPage(selectPage, InterfaceVO.class);
    }

    @Override
    public int onlineInterface(Long id) {
        //todo 上线和下线两个接口要考虑安全性，不能一直无限制的调用、访问数据库
        //因为在controller有做权限校验，所以这里就不做了
        UpdateWrapper<Interface> updateWrapper = new UpdateWrapper<>();

        updateWrapper.eq("id",id);
        updateWrapper.set("status",1);
        return interfaceMapper.update(updateWrapper);



    }

    @Override
    public int offlineInterface(Long id) {
        //因为在controller有做权限校验，所以这里就不做了
        UpdateWrapper<Interface> updateWrapper = new UpdateWrapper<>();

        updateWrapper.eq("id",id);
        updateWrapper.set("status",0);
        return interfaceMapper.update(updateWrapper);
    }

    /**
     * 用于将json格式的参数解析成一个Map
     * @param jsonString json格式的参数列表，有type表示参数类型，name表示参数名称，value表示默认值
     * @return 参数Map，外层String表示参数类型，内层的String表示参数名称，value为默认值
     */
    public Map<String, Map<String,Object>> parseParameters(String jsonString){

        // 创建Gson实例
        Gson gson = new Gson();

        // 解析Json串，提取parameters列表
        Type typeToken = new TypeToken<List<Map<String, Object>>>(){}.getType();
        List<Map<String, Object>> parameters  = gson.fromJson(jsonString, typeToken);

        // 将parameters列表解析为所需的Map格式
        Map<String, Map<String, Object>> paramMap = new HashMap<>();
        for (Map<String, Object> param : parameters) {
            String type = (String) param.get("type");
            String name = (String) param.get("name");
            Object defaultValue = param.get("defaultValue");

            Map<String, Object> typeMap = paramMap.computeIfAbsent(type, k -> new HashMap<>());
            typeMap.put(name, defaultValue);
        }

        return paramMap;
    }

    /**
     * 追加内容到文件的最后一个}之前
     * @param filePath 文件路径
     * @param textToAdd 要追加的内容
     */
    public void appendToFile(String filePath, String textToAdd) {

        File file = new File(filePath);
        System.out.println("要写入的类路径为"+file.getAbsoluteFile());
        StringBuilder sb = new StringBuilder();

        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {

            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }

            int lastIndexOfBracket = sb.lastIndexOf("}");

            // remove the last bracket
            sb.deleteCharAt(lastIndexOfBracket);

            // add new method
            sb.append(textToAdd);

            // add } back
            sb.append("}");

        } catch (IOException e) {
            e.printStackTrace();
        }

        try(BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {

            writer.write(sb.toString());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
